﻿using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using StackExchange.Redis;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace 日志的使用.自定义的内容
{
    /// <summary>
    /// 添加使用Redis
    /// 添加Nuget包： NuGet\Install-Package Microsoft.Extensions.Caching.StackExchangeRedis
    /// </summary>
    public static class RegisterRedis
    {
        private static IConnectionMultiplexer conMultiplexer;
        private static string? instanceName;
        public static void AddRedis(this WebApplicationBuilder builder)
        {
            //可以有多个IP:Port,但密码只有一个，查看底层代码就是这样处理的,注意String中的内容名称是以小写开头的
            //IConnectionMultiplexer conMultiplexer = ConnectionMultiplexer.Connect("192.168.1.6:6379,192.168.1.7:6379,password=tw3423,defaultDatabase=1,connectTimeout=100");       

            conMultiplexer = ConnectionMultiplexer.Connect(builder.Configuration.GetSection("redis:conString").Get<string>());
            instanceName = builder.Configuration.GetSection("redis:instanceName").Get<string>();
            builder.Services.AddStackExchangeRedisCache(options =>
            {
                ConfigurationOptions cfgOpts = new ConfigurationOptions();
                //cfgOpts.EndPoints.Add("192.168.1.6:6379");
                //cfgOpts.EndPoints.Add("192.168.1.7:6379");
                //cfgOpts.Password = "123456";
                //cfgOpts.DefaultDatabase = 2;
                //cfgOpts.ConnectTimeout = 1000;
                // options.ConfigurationOptions = cfgOpts;
                options.InstanceName = instanceName;  //设置RedisKey的前缀               
                options.ConnectionMultiplexerFactory = () => { return Task.FromResult(conMultiplexer); };
            });
        }

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cache"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static async Task<T?> GetAsync<T>(this IDistributedCache cache, string key)
        {
            string redisResult = await cache.GetStringAsync(key);
            return redisResult.ParseJson<T>();
        }

        /// <summary>
        /// 保存缓存
        /// </summary>    
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expires"></param>
        /// <param name="slidExpires"></param>
        /// <returns></returns>
        public static Task SetAsync<T>(this IDistributedCache cache, string key, T value, TimeSpan? expires = null, TimeSpan? slidExpires = null)
        {

            DistributedCacheEntryOptions options = new DistributedCacheEntryOptions();
            options.SetAbsoluteExpiration(expires ?? TimeSpan.FromDays(1));
            if (null != slidExpires) options.SetSlidingExpiration(slidExpires ?? TimeSpan.FromMinutes(0));
            return SetAsync(cache, key, value, options);
        }


        /// <summary>
        /// 保存缓存
        /// </summary>      
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public static Task SetAsync<T>(this IDistributedCache cache, string key, T value, DistributedCacheEntryOptions options)
        {
            return cache.SetStringAsync(key, value.ToJsonString(), options);
        }

        /// <summary>
        /// 获取，如果为空就获取并保存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cache"></param>
        /// <param name="key"></param>
        /// <param name="factory"></param>
        /// <returns></returns>
        public static async Task<T> GetOrCreateAsync<T>(this IDistributedCache cache, string key, Func<DistributedCacheEntryOptions, T> factory)
        {
            var result = await GetAsync<T>(cache, key);
            if (null == result)
            {
                DistributedCacheEntryOptions options = new DistributedCacheEntryOptions();
                result = factory.Invoke(options);
                await SetAsync(cache, key, result, options);
            }
            return result;
        }


        /// <summary>
        /// 判断缓存是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static async Task<bool> KeyExistsByRedisAsync(this IDistributedCache cache, string key)
        {
            var database = conMultiplexer.GetDatabase();
            return await database.KeyExistsAsync(instanceName + key);
        }



    }
}
